/*
 *文件作用: 声明内部类型和API实现
 */

#include "leptjson.h"
#include <assert.h>
#include <errno.h>  //error, ERANGE
#include <math.h>   // HUGE_VAL
#include <stdio.h>
#include <stdlib.h>  //strtod()

//=========================Start: 宏=====================
//是否为数字 0~9
#define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9')

//是否为数字1~9
#define ISDIGIT1TO9(ch) (((ch) >= '1') && ((ch) <= '9'))
//==========================End: 宏=======================

//将json的相关数据封装，减少解析函数之间传递的参数个数
//暂只存放json字符串
typedef struct {
    const char* json;
} lept_context;

//比较c和ch是否相等
#define EXPECT(context, ch)                                                    \
    do {                                                                       \
        assert(*context->json == (ch));                                        \
        *context->json++;                                                      \
    } while (0)

//解析whitespace
static void lept_parse_whitespace(lept_context* c) {
    const char* p = c->json;
    //解析space, tab, line feed, carriage return
    while ((*p != '\0') &&
           (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) {
        p++;
    }
    c->json = p;
}

//对 true, false, null 的合并解析
//参数表:
//  c: 保存json串的内容
//  v: 解析后保存数据的节点
//  expect_json: 期待的字符串
//  type_type: 期待的解析结果类型
static int lept_parse_literal(lept_context* context, lept_value* v,
                              char* expect_json, lept_type expect_type) {
    EXPECT(context, *expect_json);
    // context->json++;
    expect_json++;
    while ((*context->json != '\0') && (*expect_json != '\0')) {
        if (*context->json != *expect_json) {
            return LEPT_PARSE_INVALID_VALUE;
        }
        context->json++;
        expect_json++;
    }
    //若未完成解析，表示json字符串非法
    if (*expect_json != '\0') {
        return LEPT_PARSE_INVALID_VALUE;
    }
    v->type = expect_type;
    return LEPT_PARSE_OK;
}

//校验 json数字格式
static int validate_number(const char* json) {
    int neg_tag = 0;   //负号标志
    int int_tag = 0;   //整数标志
    int frac_tag = 0;  //小数标志
    int exp_tag = 0;   //指数标志

    //在json数字格式中，以 + 正号开头不合法
    if (*json == '+') {
        return LEPT_PARSE_INVALID_VALUE;
    } else if (*json == '-') {
        neg_tag = 1;
        json++;
    }

    //检测整数
    if (*json == '0') {
        //如果整数部分以 0 开头, 则只能是单个0, 否则非法
        json++;
        int_tag = 1;
    } else if (ISDIGIT1TO9(*json)) {
        //若已 1~9 的数字开头, 则后续可以是任意数量的连续的 0~9 的数字
        json++;
        while (ISDIGIT(*json)) {
            json++;
        }
        int_tag = 1;
    } else {
        // json数字格式中, 不含整数部分是不合法的
        return LEPT_PARSE_INVALID_VALUE;
    }

    //检测小数部分
    if (*json == '.') {
        json++;
        if (!ISDIGIT(*json)) {
            return LEPT_PARSE_INVALID_VALUE;
        }
        while (ISDIGIT(*json)) {
            json++;
        }
        frac_tag = 1;
    }

    //检测指数部分: 以 e 或 E 开头, 后可跟 + 正号或 - 负号, 后接任意位 0~9的整数
    if (*json == 'e' || *json == 'E') {
        json++;
        if (*json == '+' || *json == '-') {
            json++;
        }
        while (ISDIGIT(*json)) {
            json++;
        }
        if (*json != '\0') {
            return LEPT_PARSE_INVALID_VALUE;
        }
        exp_tag = 1;
    }
    return LEPT_PARSE_OK;
}

// 解析json数字
static int lept_parse_number(lept_context* c, lept_value* v) {
    char* end;
    //校验数字格式
    int ret_value;
    if ((ret_value = validate_number(c->json)) != LEPT_PARSE_OK) {
        return ret_value;
    }

    errno = 0;
    v->number = strtod(
        c->json, &end);  // 处理成功时, 返回正确处理的浮点结果。若处理失败,
                         // 则返回0, 并令c->json = end;
    if (errno == ERANGE && v->number == HUGE_VAL) {
        return LEPT_PARSE_NUMBER_TOO_BIG;
    }
    // if (c->json == end) {
    //     return LEPT_PARSE_INVALID_VALUE;  //处理失败, 数字格式非法
    // }
    c->json = end;
    v->type = LEPT_NUMBER;
    return LEPT_PARSE_OK;
}

//解析 value = null / false / true
static int lept_parse_value(lept_context* c, lept_value* v) {
    switch (*c->json) {
        case 't': return lept_parse_literal(c, v, "true", LEPT_TRUE);
        case 'f': return lept_parse_literal(c, v, "false", LEPT_FALSE);
        case 'n': return lept_parse_literal(c, v, "null", LEPT_NULL);
        case '\0': return LEPT_PARSE_EXPECT_VALUE;  //没有value
        default:
            return lept_parse_number(c, v);  //其余值交由 json数字解析模块 处理
    }
}

//按照 whitespace - value - whitespace 的格式对json字符串进行解析
int lept_parse(lept_value* v, const char* json) {
    lept_context c;
    assert(v != NULL);  //第一个值不能是null
    c.json = json;
    v->type = LEPT_NULL;  //初始化为null类型
    lept_parse_whitespace(&c);
    int ret_value = lept_parse_value(&c, v);

    //若value解析成功，则继续解析value之后的所有空格，再判断是否结束。若未结束则判定为多值输入
    if (ret_value == LEPT_PARSE_OK) {
        lept_parse_whitespace(&c);
        if ((ret_value == LEPT_PARSE_OK) && (*c.json != '\0')) {
            v->type = LEPT_NULL;  //多值输入，将类型强制修改为null
            return LEPT_PARSE_ROOT_NOT_SINGULAR;
        }
    }
    return ret_value;
}

//返回节点的类型
lept_type lept_get_type(const lept_value* v) {
    return v->type;
}

//返回json数字
double lept_get_number(const lept_value* v) {
    assert((v != NULL) && v->type == LEPT_NUMBER);
    return v->number;
}